package org.ipp4j.core;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.Map;

import org.apache.commons.io.IOUtils;

public abstract class IppTools {
	private static final int STATE_NONE = 0;
	private static final int STATE_OPERATION = 1;
	private static final int STATE_JOB = 2;
	private static final int STATE_END = 3;

	private static final byte BEGIN_ATTRIBUTE_GROUP_TAG = 0x00;
	private static final byte OPERATION_ATTRIBUTE_TAG = 0x01;
	private static final byte JOB_ATTRIBUTE_TAG = 0x02;
	private static final byte END_OF_ATTRIBUTES_TAG = 0x03;

	public static byte[] extractIppHeader(InputStream stream,
			Map<String, String> attributeReplaces) throws IOException {
		ByteBuffer buffer = ByteBuffer.allocate(8192);
		byte[] fixHeader = new byte[8];
		IOUtils.read(stream, fixHeader);
		buffer.put(fixHeader);

		int state = STATE_NONE;
		while (state != STATE_END) {
			byte value = (byte) (stream.read() & 0xFF);
			buffer.put(value);
			if (value >= BEGIN_ATTRIBUTE_GROUP_TAG
					&& value <= END_OF_ATTRIBUTES_TAG) {
				switch (value) {
				case OPERATION_ATTRIBUTE_TAG:
					state = STATE_OPERATION;
				case JOB_ATTRIBUTE_TAG:
					state = STATE_JOB;
					value = (byte) (stream.read() & 0xFF);
					buffer.put(value);

					break;
				case END_OF_ATTRIBUTES_TAG:
					state = STATE_END;
					break;
				default:
					value = (byte) (stream.read() & 0xFF);
					buffer.put(value);

					break;
				}
			}

			if (state != STATE_END) {

				byte[] nameLengthBytes = new byte[2];
				IOUtils.read(stream, nameLengthBytes);
				buffer.put(nameLengthBytes);
				int nameLength = (nameLengthBytes[0] & 0xFF) << 8
						| (nameLengthBytes[1] & 0xFF);
				String name = "";
				if (nameLength > 0) {
					byte[] nameValueBytes = new byte[nameLength];
					IOUtils.read(stream, nameValueBytes);
					buffer.put(nameValueBytes);
					name = new String(nameValueBytes);
				}

				if (attributeReplaces.containsKey(name)) {
					byte[] valueLengthBytes = new byte[2];
					IOUtils.read(stream, valueLengthBytes);

					int valueLength = (valueLengthBytes[0] & 0xFF) << 8
							| (valueLengthBytes[1] & 0xFF);
					byte[] valueBytes = new byte[valueLength];
					IOUtils.read(stream, valueBytes);

					String replaceValue = attributeReplaces.get(name);
					short shortValue = (short) replaceValue.length();
					buffer.putShort(shortValue);
					buffer.put(replaceValue.getBytes());
				} else {

					// check the name and do something;
					byte[] valueLengthBytes = new byte[2];
					IOUtils.read(stream, valueLengthBytes);
					buffer.put(valueLengthBytes);
					int valueLength = (valueLengthBytes[0] & 0xFF) << 8
							| (valueLengthBytes[1] & 0xFF);
					byte[] valueBytes = new byte[valueLength];
					IOUtils.read(stream, valueBytes);
					buffer.put(valueBytes);

				}
			}
		}
		int current = buffer.position();
		buffer.rewind();
		byte[] result = new byte[current];
		buffer.get(result, 0, current);
		return result;
	}
}
